import numpy

from manimlib import *


class ShowSuccessively(ShowCreation):
    CONFIG = {"lag_ratio": 0.1}

    def interpolate_submobject(self, submob, start_submob, alpha):
        points1 = start_submob.get_subcurve(alpha ** 0.8, alpha ** 0.5).get_points()
        points2 = start_submob.get_subcurve(0, alpha).get_points()
        submob.data["points"] = np.vstack((points1, points2))


class RasterPlay(ShowPartial):
    CONFIG = {
        "lag_ratio": 0
    }

    def begin(self):
        super().begin()
        if not self.should_match_start:
            self.mobject.lock_matching_data(self.mobject, self.starting_mobject)

    def finish(self):
        super().finish()
        self.mobject.unlock_data()

    def get_partials(self, submob, start_submob, alpha):
        n = 10
        submob.clear_points()
        for i in range(n // 2):
            itp1 = interpolate(i / n, (i + 1) / n, alpha)
            itp2 = interpolate(1 - i / n, 1 - (i + 1) / n, alpha)
            p1 = start_submob.get_subcurve((i / n), itp1).get_points()
            p2 = start_submob.get_subcurve(itp2, 1 - (i / n)).get_points()
            submob.append_points(p1)
            submob.add_line_to(p2[0])
            submob.append_points(p2)
            submob.add_line_to(p1[0])

    def interpolate_submobject(self, submob, start_submob, alpha):
        self.get_partials(submob, start_submob, alpha)


class TestRaster(Scene):
    def construct(self):
        squ = Square(fill_opacity=1).scale(3)
        self.play(RasterPlay(squ), run_time=3)


class MyShowCreation(ShowCreation):
    def interpolate_submobject(self, submob, start_submob, alpha):
        submob.pointwise_become_partial(
            start_submob, *self.get_bounds(alpha)
        )
        submob.close_path()


class TestPartial(Scene):
    def construct(self):
        squ = Square(fill_opacity=1).scale(2.5)
        t = Text("Default ShowCreation").to_corner(DR)
        self.play(
            ShowCreation(squ),
            Write(t),
            run_time=2
        )
        self.wait()
        self.play(FadeOut(squ))
        self.play(
            MyShowCreation(squ),
            t.animate.become(Text("My ShowCreation").to_corner(DR)),
            run_time=2
        )
        self.play(FadeOut(squ))


class ReDrawBorderThenFill(DrawBorderThenFill):

    def get_partial_curves(self, submob, start_submob, alpha):
        points1 = start_submob.get_subcurve((alpha * 2) ** 0.5, (2 * alpha) ** 0.3).get_points()
        # points2 = start_submob.get_subcurve((alpha * 2) ** 1.1, (2 * alpha) ** 0.9).get_points()
        points3 = start_submob.get_subcurve(0, (alpha * 2) ** 1.3).get_points()
        submob.data["points"] = np.vstack((points1, points3))

    def interpolate_submobject(self, submob, start, outline, alpha):
        index, subalpha = integer_interpolate(0, 2, alpha)

        if index == 1 and self.sm_to_index[hash(submob)] == 0:
            # First time crossing over
            submob.set_data(outline.data)
            submob.unlock_data()
            if not self.mobject.has_updaters:
                submob.lock_matching_data(submob, start)
            submob.needs_new_triangulation = False
            self.sm_to_index[hash(submob)] = 1

        if index == 0:
            self.get_partial_curves(submob, outline, alpha)
            # submob.pointwise_become_partial(outline, 0, subalpha)
        else:
            submob.interpolate(outline, start, subalpha)


class TestShow(Scene):
    def construct(self):
        cir = Text("Hello World").scale(3)
        # cir = Circle().scale(3)
        self.play(ReDrawBorderThenFill(cir), run_time=4)
        # self.wait()


class TestColor(Scene):
    def construct(self):
        squ = Square(fill_opacity=1).scale(3)
        squ.set_color_by_code("""
        color = vec4(0, 0, 0, 1);
        color.g += (point.y + 3.0) / 6.0; 
        color.b += (point.x + 3.0) / 6.0;
        """)
        self.add(squ)


class TestPoints(Scene):
    def construct(self):
        # obj = Text("Hello", font="Consolas", fill_opacity=0, stroke_width=2).scale(4)
        obj = Circle()
        obj.pointwise_become_partial(obj.copy(), 0.875, 1)

        self.add(obj)
